﻿using System.Linq.Expressions;

namespace LaoLuo
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    public static class Number
    {
        public static bool IsZero<T>(this T number)
            where T : struct, IComparable, IFormattable, IConvertible
        {
            return number.CompareTo(default(T)) == 0;
        }

        public static Number<T> ToNumber<T>(this T number)
            where T : struct, IComparable, IFormattable, IConvertible
        {
            return number;
        }

        public static T ToValue<T>(this Number<T> number)
            where T : struct, IComparable, IFormattable, IConvertible
        {
            return number;
        }
    }

    public struct Number<T>
        where T : struct, IComparable, IFormattable, IConvertible
    {
        private readonly T _value;

        public Number(T number)
        {
            ThrowHelper.ThrowIfNotNumericType<T>();

            _value = number;
        }

        public T Value
        {
            get { return _value; }
        }

        #region operators

        public static implicit operator T(Number<T> number)
        {
            return number.Value;
        }

        public static implicit operator Number<T>(T number)
        {
            return new Number<T>(number);
        }

        public static Number<T> operator ++(Number<T> number)
        {
            return Operator.Increase(number.Value);
        }

        public static Number<T> operator --(Number<T> number)
        {
            return Operator.Decrease(number.Value);
        }

        public static Number<T> operator +(Number<T> a, Number<T> b)
        {
            return Operator.Add(a.Value, b.Value);
        }

        public static Number<T> operator -(Number<T> a, Number<T> b)
        {
            return Operator.Subtract(a.Value, b.Value);
        }

        public static Number<T> operator *(Number<T> a, Number<T> b)
        {
            return Operator.Multiply(a.Value, b.Value);
        }

        public static Number<T> operator /(Number<T> a, Number<T> b)
        {
            return Operator.Divide(a.Value, b.Value);
        }

        public static Number<T> operator %(Number<T> a, Number<T> b)
        {
            return Operator.Modulo(a.Value, b.Value);
        }

        public static bool operator >(Number<T> a, Number<T> b)
        {
            return Operator.GreaterThan(a.Value, b.Value);
        }

        public static bool operator >=(Number<T> a, Number<T> b)
        {
            return Operator.GreaterThanOrEqual(a.Value, b.Value);
        }

        public static bool operator <(Number<T> a, Number<T> b)
        {
            return Operator.LessThan(a.Value, b.Value);
        }

        public static bool operator <=(Number<T> a, Number<T> b)
        {
            return Operator.LessThanOrEqual(a.Value, b.Value);
        }

        public static bool operator ==(Number<T> a, Number<T> b)
        {
            return Operator.Equal(a.Value, b.Value);
        }

        public static bool operator !=(Number<T> a, Number<T> b)
        {
            return Operator.NotEqual(a.Value, b.Value);
        }

        #endregion
    }
}
